package com.example.core.aspect;

import com.example.core.annotation.HasPerm;
import com.example.core.exception.HotelException;
import com.example.core.feign.UserFeignClient;
import com.example.core.utils.ServletUtils;
import com.example.model.BaseEntity;
import com.example.redis.utils.CacheUtil;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

import static com.example.model.constants.CodeConstants.CREATED_UPDATED_ERROR;
import static com.example.model.constants.KeyConstants.KEY_NAME;
import static com.example.model.constants.KeyConstants.KEY_PERMISSION;

@Aspect
@Component
@Profile("perm")
public class UserAspect {

    @Autowired
    private UserFeignClient userFeignClient;

    @Autowired
    private CacheUtil cacheUtil;

    @Pointcut("@annotation(com.example.core.annotation.HasPerm)")
    public void verifyPointCut() {}

    @Pointcut("execution(int com.example..*.insert(..)) && !execution(* com.example.payment..*.insert(..))")
    public void insertPointCut() {}

    @Pointcut("execution(int com.example..*.update(..))")
    public void updatePointCut() {}

    @Before("verifyPointCut()")
    public void verifyPerm(JoinPoint joinPoint) {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();
        HasPerm hasPerm = method.getAnnotation(HasPerm.class);
        String permission = hasPerm.value();
        String token = ServletUtils.getRequest().getHeader("Authorization");
        List<String> permissions = cacheUtil.getCacheList(KEY_PERMISSION + token);
        if (permissions == null) {
            permissions = new ArrayList<>();
        }
        if (permissions.contains(permission)) {
            return;
        } else {
            if (!userFeignClient.hasPerm(permission, ServletUtils.getRequest().getHeader("Authorization"))) {
                throw new HotelException(401, "没有权限");
            } else {
                cacheUtil.setCacheListRight(KEY_PERMISSION + token, permission);
            }
        }
    }

    @Before("insertPointCut()")
    public void insertBefore(JoinPoint joinPoint) {
        BaseEntity base = getBaseEntity(joinPoint);
        String username = getUsername();
        base.setCreatedBy(username);
        base.setCreatedTime(LocalDateTime.now());
    }

    @Before("updatePointCut()")
    public void updateBefore(JoinPoint joinPoint) {
        BaseEntity base = getBaseEntity(joinPoint);
        String username = getUsername();
        base.setUpdatedBy(username);
        base.setUpdatedTime(LocalDateTime.now());
    }

    private BaseEntity getBaseEntity(JoinPoint joinPoint) {
        Object[] args = joinPoint.getArgs();
        BaseEntity base = null;
        if (args[0] instanceof BaseEntity) {  // 插入对象只有一个参数
            base = (BaseEntity) args[0];
        } else {
            throw new HotelException(CREATED_UPDATED_ERROR, "数据错误");
        }
        return base;
    }

    private String getUsername() {
        String username = cacheUtil.getObject(KEY_NAME+ ServletUtils.getRequest().getHeader("Authorization"));
        if (username == null) {
            username = userFeignClient.getLoginUsername(ServletUtils.getRequest().getHeader("Authorization"));
            cacheUtil.setObject(KEY_NAME+ ServletUtils.getRequest().getHeader("Authorization"), username);
        }
        return username;
    }

}
